/*
 * CorrHistogramm.cpp
 *
 *  Created on: 13.03.2013
 *      Author: mag
 */

#include <limits.h>
#include <string>
#include <sstream>
#include <stdarg.h>

#include "Histogram2.h"

#include "Logger.h"
DECLARE_LOG_SUPPORT(MODULES)

Histogram2::Histogram2(int chan1, int chan2,
		               long long _binwidth, long long _timespan,unsigned _buffer_size)
: channel1(chan1), channel2(chan2),
  binwidth(_binwidth),
  timespan(_timespan),
  buffer_size(_buffer_size)
{
	debug("Histogram2 created.");

	ch1_buffer=new long long[buffer_size];
	ch2_buffer=new long long[buffer_size];

	histogram1=new long long[buffer_size];
	histogram2=new long long[buffer_size];

	clear();

	start();
}

Histogram2::~Histogram2() {
	delete [] ch1_buffer;
	delete [] ch2_buffer;
	delete [] histogram1;
	delete [] histogram2;

}

const char *Histogram2::getClassName()  {
	return "Histogram2";
}

const char * Histogram2::getScpiCommand() {
	return ":CONFigure:CHISTOgram";
}

std::string Histogram2::getScpiParameters() {
	std::stringstream ss;
	ss << "chan" << channel1 << ",chan" << channel2 << ",(" << binwidth << ',' << timespan << ',' << buffer_size << ')';
	return ss.str();
}

/**
 * get module meta data as array of longs..
 * format:
 * 		[0] channel1
 * 		[1] channel2
 * 		[2] binwidth
 * 		[3] timespan
 * 		[4] total click count
 * 		[5] channel1 click count
 * 		[6] channel2 click count
 * 		[7] duration
 * 		[8] time of first click
 * 		[9] time of last click
 */
void Histogram2::getMeta(long long **ARGOUTVIEWM_ARRAY2, int *DIM1) {

	const int sz=10;
	long long *arr = new long long[sz];

	synchronized(*this) {
		long long *ptr=arr;
		*ptr++=channel1;
		*ptr++=channel2;
		*ptr++=binwidth;
		*ptr++=timespan;
		*ptr++=ch1_count+ch2_count;
		*ptr++=ch1_count;
		*ptr++=ch2_count;
		*ptr++=last_time-first_time;
		*ptr++=first_time;
		*ptr++=last_time;
	}

	*ARGOUTVIEWM_ARRAY2 = arr;
	*DIM1 = sz;
}

/**
 * get measurement result as 2dimensional long array.
 * format:
 *   [tm][0] - time window
 *   [tm][1] - squared autocorrelated counts
 *   [tm][2] - scaled autocorrelated counts  ???
 *   [tm][3] - autocorrelated channel2 clicks ???
 *
 */
void Histogram2::getData(long long **ARGOUTVIEWM_ARRAY2, int *DIM1, int *DIM2) {
	synchronized (*this) {
		if (ch1_count>0 && ch2_count>0) {
			int sz = binwidth;
			long long *arr = new long long[sz*4];

			//TODO:
			double factor=1.0 / ((float)ch1_count * (float)ch2_count *	(float) timespan / (float) (last_time-first_time) );
			long long *p=arr;
			for (int n=0; n<binwidth; ++n) {
				*p++ = n*timespan;
				*p++ =  histogram1[n];
				*p++ = (long long) ((double) histogram1[n] * factor);
				*p++ =  histogram2[n];
			}

			*ARGOUTVIEWM_ARRAY2 = arr;
			*DIM1 = sz;
			*DIM2 = 2;

		} else {

			*ARGOUTVIEWM_ARRAY2 = 0;
			*DIM1 = 0;
			*DIM2 = 4;
		}
	}
}

void Histogram2::clear() {
	synchronized (*this) {
		ch1_count = ch2_count = 0;
		first_time=last_time=0;

		clear_buffer();
		for (int n=0; n<binwidth; ++n) {
			histogram1[n]=histogram1[n]=0;
		}
	}
}

void Histogram2::clear_buffer() {
	for (unsigned n=0; n<buffer_size; ++n) {
		ch1_buffer[n] = ch2_buffer[n] = LLONG_MAX;
	}
}

void Histogram2::next(Tag* tag, int count, long long time) {
	// at this point module is already synchronized
	while(count>0) {
		if(tag->overflow) {
			clear_buffer();

		} else {

			if (first_time==0)
				first_time=tag->time;
			last_time=tag->time;

			if(tag->chan == channel1) {
				// store in buffer
				ch1_buffer[ch1_count % buffer_size]=tag->time;
				++ch1_count;
			}

			if(tag->chan == channel2) {
				// store in buffer
				ch2_buffer[ch2_count % buffer_size]=tag->time;
				++ch2_count;

				// walk thru ch1 history
				for (unsigned n=0; n<buffer_size; ++n) {
					unsigned idx=(ch1_count-n) % buffer_size;
					long long diff=(tag->time - ch1_buffer[idx]) / timespan;
					if (diff<binwidth) {
						++histogram1[diff];	// count if within binwidth
					} else
						break;				// break when older click encountered
				}

				// walk thru ch2 history
				for (unsigned n=0; n<buffer_size; ++n) {
					unsigned idx=(ch2_count-n) % buffer_size;
					long long diff=(tag->time - ch2_buffer[idx]) / timespan;
					if (diff<binwidth) {
						++histogram2[diff];	// count if within binwidth
					} else
						break;				// break when older click encountered
				}

			}
		}
	}
}
